% \iffalse meta-comment
% !TEX program  = XeLaTeX
%<*internal>
\iffalse
%</internal>
%<*readme>
jiazhu
======

`jiazhu` is a LaTeX package written to support `jiazhu` (splitted annotation or
inline cutting note, 夹注/双行夹注 in simplified Chinese, 割注/warichū in Japanese)
typesetting for CJK scripts.

You can read the package manual (in Chinese) for more detailed explanations.

Contributing
------------

This package is a part of the [ctex-kit](https://github.com/CTeX-org/ctex-kit) project.

Issues and pull requests are welcome.

Copyright and Licence
---------------------

    Copyright (C) 2018-2019 by Qing Lee <sobenlee@gmail.com>
    ----------------------------------------------------------------------

    This work may be distributed and/or modified under the
    conditions of the LaTeX Project Public License, either
    version 1.3c of this license or (at your option) any later
    version. This version of this license is in
       http://www.latex-project.org/lppl/lppl-1-3c.txt
    and the latest version of this license is in
       http://www.latex-project.org/lppl.txt
    and version 1.3 or later is part of all distributions of
    LaTeX version 2005/12/01 or later.

    This work has the LPPL maintenance status `maintained'.

    The Current Maintainer of this work is Qing Lee.

    This package consists of the file  jiazhu.dtx,
                 and the derived files jiazhu.sty,
                                       jiazhu.pdf,
                                       jiazhu.ins,
                                       jiazhu-test.tex, and
                                       README.md (this file).

%</readme>
%<*internal>
\fi
\begingroup
  \def\temp{LaTeX2e}
\expandafter\endgroup\ifx\temp\fmtname\else
\csname fi\endcsname
%</internal>
%<*install>

\input ctxdocstrip %

\preamble

    Copyright (C) 2018-2019 by Qing Lee <sobenlee@gmail.com>
--------------------------------------------------------------------------

    This work may be distributed and/or modified under the
    conditions of the LaTeX Project Public License, either
    version 1.3c of this license or (at your option) any later
    version. This version of this license is in
       http://www.latex-project.org/lppl/lppl-1-3c.txt
    and the latest version of this license is in
       http://www.latex-project.org/lppl.txt
    and version 1.3 or later is part of all distributions of
    LaTeX version 2005/12/01 or later.

    This work has the LPPL maintenance status `maintained'.

    The Current Maintainer of this work is Qing Lee.

--------------------------------------------------------------------------

\endpreamble

\postamble

    This package consists of the file  jiazhu.dtx,
                 and the derived files jiazhu.sty,
                                       jiazhu.pdf,
                                       jiazhu.ins,
                                       jiazhu-test.tex, and
                                       README.md (this file).
\endpostamble

\declarepostamble\emptypostamble
\endpostamble

\generate
  {
%</install>
%<*internal>
    \usedir{source/latex/jiazhu}
    \file{jiazhu.ins}       {\from{\jobname.dtx}{install}}
%</internal>
%<*install>
    \usedir{tex/latex/jiazhu}
    \file{jiazhu.sty}       {\from{\jobname.dtx}{package}}
    \usepreamble\emptypreamble
    \usepostamble\emptypostamble
    \usedir{doc/latex/jiazhu}
    \file{jiazhu-test.tex}  {\from{\jobname.dtx}{test}}
    \nopreamble\nopostamble
    \file{README.md}        {\from{\jobname.dtx}{readme}}
  }

\endbatchfile
%</install>
%<*internal>
\fi
%</internal>
%<package>\NeedsTeXFormat{LaTeX2e}
%<package>\RequirePackage{expl3}
%<+package>\GetIdInfo$Id$
%<package>  {Jiazhu/Warichu Support}
%<package>\ProvidesExplPackage{\ExplFileName}
%<package>  {\ExplFileDate}{0}{\ExplFileDescription}
%<*driver>
\documentclass{ctxdoc}
\usepackage{jiazhu}

\jiazhuset { opening = 〔 , closing = 〕 }

\begin{document}
  \DocInput{\jobname.dtx}
  \IndexLayout
  \PrintIndex
\end{document}
%</driver>
% \fi
%
% \CheckSum{827}
% \GetFileId{jiazhu.sty}
%
% \title{\bfseries\pkg{jiazhu} 宏包}
% \author{李清\\ \path{sobenlee@gmail.com}}
% \date{\filedate\qquad\fileversion\thanks{\ctexkitrev{\ExplFileVersion}.}}
% \maketitle
%
% \begin{documentation}
%
% \section{简介}
%
% \pkg{jiazhu} 是一个 \LaTeX 宏包，用于支持\jiazhu{双行夹注}或者\jiazhu{割注}排版。
%
% \section{基本用法}
%
% \begin{function}{\jiazhu}
%   \begin{syntax}
%     \cs{jiazhu} \oarg{键值选项} \Arg{夹注内容}
%   \end{syntax}
% \end{function}
%
% \begin{function}{\jiazhuset}
%   \begin{syntax}
%     \cs{jiazhuset} \Arg{键值选项}
%   \end{syntax}
% \end{function}
%
% \begin{function}{format}
%   \begin{syntax}
%     format = \Arg{格式命令}
%   \end{syntax}
% \end{function}
%
% \begin{function}{lines}
%   \begin{syntax}
%     lines = \Arg{正整数}
%   \end{syntax}
% \end{function}
%
% \begin{function}{ratio}
%   \begin{syntax}
%     ratio = \Arg{数字}
%   \end{syntax}
% \end{function}
%
% \begin{function}{beforeskip}
%   \begin{syntax}
%     beforeskip = \Arg{弹性间距}
%   \end{syntax}
% \end{function}
%
% \begin{function}{afterskip}
%   \begin{syntax}
%     afterskip = \Arg{弹性间距}
%   \end{syntax}
% \end{function}
%
% \begin{function}{opening}
%   \begin{syntax}
%     opening = \Arg{前置内容}
%   \end{syntax}
% \end{function}
%
% \begin{function}{closing}
%   \begin{syntax}
%     closing = \Arg{后置内容}
%   \end{syntax}
% \end{function}
%
% \begin{function}{bracketratio}
%   \begin{syntax}
%     bracketratio = \Arg{数字}
%   \end{syntax}
% \end{function}
%
% \begin{function}{baselineshift}
%   \begin{syntax}
%     baselineshift = \Arg{尺寸}
%   \end{syntax}
% \end{function}
%
% \begin{function}{alignment}
%   \begin{syntax}
%     alignment = <(justified)|left|right|centered|distributed>
%   \end{syntax}
% \end{function}
%
% \begin{function}{shortcut}
%   \begin{syntax}
%     shortcut  = \Arg{字符}
%     shortcut  = \{<开始字符><结束字符>\}
%     shortcut- = \Arg{字符列表}
%   \end{syntax}
% \end{function}
%
% \end{documentation}
%
% \StopEventually{}
%
% \begin{implementation}
%
% \section{代码实现}
%
%    \begin{macrocode}
%<*package>
%<@@=jiazhu>
%    \end{macrocode}
%
%    \begin{macrocode}
\msg_new:nnn { jiazhu } { l3-too-old }
  {
    Support~package~'expl3'~too~old. \\\\
    Please~update~an~up~to~date~version~of~the~bundles\\\\
    'l3kernel'~and~'l3packages'\\\\
    using~your~TeX~package~manager~or~from~CTAN.
  }
\@ifpackagelater { expl3 } { 2019/03/05 } { }
  { \msg_error:nn { jiazhu } { l3-too-old } }
%    \end{macrocode}
%
%    \begin{macrocode}
\RequirePackage { xparse }
%    \end{macrocode}
%
% \begin{macro}[int]{\jiazhu:nn}
% 主要函数。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \jiazhu:nn
  {
    \mode_if_vertical:TF
      { \@@_vertical_mode:nn }
      {
        \mode_if_horizontal:TF
          {
            \mode_if_inner:TF
              { \@@_inner_mode:nn }
              { \@@_horizontal_mode:nn }
          }
          { \@@_inner_mode:nn }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_vertical_mode:nn}
% 竖直模式下不用计算上一段最后一行的宽度，但要注意处理 \tn{parindent}。
%    \begin{macrocode}
\cs_new_protected:Npn \@@_vertical_mode:nn
  {
    \mode_leave_vertical:
    \group_begin:
      \@@_set_line_width:
      \bool_set_true:N \l_@@_full_line_bool
      \bool_set_false:N \l_@@_before_skip_bool
      \dim_set:Nn \l_@@_remaining_width_dim
        {
          \int_compare:nNnTF \tex_lastnodetype:D = \c_one_int
            { \l_@@_line_width_dim - \tex_parindent:D }
            { \l_@@_line_width_dim }
        }
      \@@_boot:nn
  }
\bool_new:N \l_@@_full_line_bool
\dim_new:N \l_@@_remaining_width_dim
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_horizontal_mode:nn}
% 水平模式下需要获取最后一行的宽度，以便将夹注放到段落的后面。
%    \begin{macrocode}
\cs_new_protected:Npn \@@_horizontal_mode:nn
  {
    \group_begin:
      \@@_extract_previous_line_width:
      \@@_set_line_width:
      \dim_set_eq:NN \l_@@_remaining_width_dim \l_@@_line_width_dim
      \int_compare:nNnTF \tex_lastnodetype:D = { 12 }
        {
          \bool_set_false:N \l_@@_full_line_bool
          \bool_set_true:N \l_@@_before_skip_bool
          \dim_sub:Nn \l_@@_remaining_width_dim
            { \g_@@_previous_line_width_dim }
        }
        {
          \bool_set_true:N \l_@@_full_line_bool
          \bool_set_false:N \l_@@_before_skip_bool
        }
      \@@_boot:nn
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_inner_mode:nn}
% 在内部水平或数学模式下，直接将夹注分行输出。
%    \begin{macrocode}
\cs_new_protected:Npn \@@_inner_mode:nn
  {
    \group_begin:
      \bool_set_false:N \l_@@_full_line_bool
      \int_compare:nNnTF \tex_lastnodetype:D = { -1 }
        { \bool_set_false:N \l_@@_before_skip_bool }
        { \bool_set_true:N \l_@@_before_skip_bool }
      \dim_set_eq:NN \l_@@_remaining_width_dim \c_max_dim
      \@@_boot:nn
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_set_line_width:}
% 当前行的宽度，\tn{hsize} 与 \tn{linewidth} 可能不一致，我们取其较小值。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_set_line_width:
  {
    \dim_set:Nn \l_@@_line_width_dim
      {
          \dim_min:nn { \tex_hsize:D } { \linewidth }
        - \tex_leftskip:D
        - \tex_rightskip:D
      }
  }
\dim_new:N \l_@@_line_width_dim
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_extract_previous_line_width:}
% 我们通过在行间数学模式中的 \tn{predisplaysize} 来获取上一行的宽度。
% 目前的 \tn{parshape} 仅考虑 \LaTeX 的列表环境。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_extract_previous_line_width:
  {
    \group_begin:
      \skip_set_eq:NN \tex_parfillskip:D \c_@@_fil_skip
      \c_math_toggle_token \c_math_toggle_token
        \dim_gset_eq:NN \g_@@_previous_line_width_dim \tex_predisplaysize:D
        \int_set:Nn \tex_predisplaypenalty:D  { 1000 }
        \int_set:Nn \tex_postdisplaypenalty:D { 1000 }
        \skip_set:Nn \tex_abovedisplayskip:D
          {
            \dim_compare:nNnTF
              { \dim_abs:n { \g_@@_previous_line_width_dim } } < \c_max_dim
              { - \l_@@_shift_dim - \tex_baselineskip:D }
              { - \l_@@_shift_dim }
          }
        \skip_set:Nn \tex_belowdisplayskip:D { - \tex_baselineskip:D }
        \skip_set_eq:NN \tex_abovedisplayshortskip:D \tex_abovedisplayskip:D
        \skip_set_eq:NN \tex_belowdisplayshortskip:D \tex_belowdisplayskip:D
      \c_math_toggle_token \c_math_toggle_token
    \group_end:
    \int_set:Nn \tex_prevgraf:D { \tex_prevgraf:D - 3 }
    \dim_compare:nNnTF
      { \dim_abs:n { \g_@@_previous_line_width_dim } } < \c_max_dim
      {
        \dim_gsub:Nn \g_@@_previous_line_width_dim
          {
            \int_compare:nNnTF \tex_parshape:D = \c_one_int
              { \tex_leftskip:D + 2em + \tex_parshapeindent:D \c_one_int }
              { \tex_leftskip:D + 2em }
          }
        \tex_kern:D \g_@@_previous_line_width_dim
      }
      { \dim_gzero:N \g_@@_previous_line_width_dim }
  }
\dim_new:N \g_@@_previous_line_width_dim
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_boot:nn}
% 当前行的宽度，\tn{hsize} 与 \tn{linewidth} 可能不一致，我们取其较小值。
%    \begin{macrocode}
\cs_new_protected:Npn \@@_boot:nn #1#2
  {
    \@@_tex_parameter:
    \dim_set:Nn \l_@@_outer_unit_dim { \f@size pt }
    \tl_if_novalue:nF {#1}
      { \keys_set:nn { jiazhu } {#1} }
    \linespread { 1 }
    \exp_args:Nxx \fontsize
      { \fp_eval:n { \l_@@_ratio_fp * \f@size } }
      { \fp_eval:n { \l_@@_ratio_fp * \f@baselineskip } }
    \tl_use:N \l_@@_format_tl
    \selectfont
    \hbox_set:Nn \l_@@_text_box { #2 \tex_unskip:D }
    \dim_set:Nn \l_@@_unit_dim { \f@size pt }
    \@@_make_opening_closing_box:
    \dim_set:Nn \tex_splitmaxdepth:D { \box_dp:N \strutbox }
    \skip_set:Nn \l_@@_good_break_skip
      { \c_zero_dim plus 0.5\l_@@_outer_unit_dim }
    \skip_set:Nn \l_@@_unit_stretch_skip
      { \c_zero_dim plus \l_@@_unit_dim }
    \@@_set_before_skip:
    \@@_processing:
  }
\box_new:N \l_@@_text_box
\dim_new:N \l_@@_unit_dim
\dim_new:N \l_@@_outer_unit_dim
\skip_new:N \l_@@_unit_stretch_skip
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_tex_parameter:}
% 为避免警告设置的一些 \TeX 参数。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_tex_parameter:
  {
    \@parboxrestore
    \tex_everypar:D { { \box_set_to_last:N \c_zero_int } }
    \dim_zero:N \tex_emergencystretch:D
    \dim_set_eq:NN \tex_hfuzz:D \c_max_dim
    \dim_set_eq:NN \tex_vfuzz:D \c_max_dim
    \int_set_eq:NN \tex_hbadness:D \c_max_int
    \int_set_eq:NN \tex_vbadness:D \c_max_int
    \int_set:Nn \tex_tolerance:D { 1000 }
    \skip_zero:N \tex_splittopskip:D
    \int_zero:N \tex_linepenalty:D
    \int_zero:N \tex_clubpenalty:D
    \int_zero:N \tex_widowpenalty:D
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_make_opening_closing_box:}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_make_opening_closing_box:
  {
    \tl_if_empty:NTF \l_@@_opening_tl
      { \box_clear:N \l_@@_opening_box }
      {
        \hbox_set:Nn \l_@@_opening_box
          {
            \fontsize
              { \fp_use:N \l_@@_bracket_ratio_fp \l_@@_unit_dim }
              { \c_zero_skip }
            \selectfont \l_@@_opening_tl
          }
        \dim_sub:Nn \l_@@_remaining_width_dim
          { \box_wd:N \l_@@_opening_box }
      }
    \tl_if_empty:NTF \l_@@_closing_tl
      { \box_clear:N \l_@@_closing_box }
      {
        \hbox_set:Nn \l_@@_closing_box
          {
            \fontsize
              { \fp_use:N \l_@@_bracket_ratio_fp \l_@@_unit_dim }
              { \c_zero_skip }
            \selectfont \l_@@_closing_tl \tex_unskip:D
          }
      }
  }
\cs_new_protected_nopar:Npn \@@_put_opening_box:
  {
    \bool_if:NT \l_@@_before_skip_bool
      { \skip_horizontal:N \l_@@_before_skip }
    \box_if_empty:NF \l_@@_opening_box
      { \@@_put_box:N \l_@@_opening_box }
    \cs_set_eq:NN \@@_put_opening_box: \prg_do_nothing:
  }
\cs_new_protected_nopar:Npn \@@_put_closing_box:
  {
    \box_if_empty:NF \l_@@_closing_box
      { \@@_put_box:N \l_@@_closing_box }
  }
\cs_new_protected:Npn \@@_put_box:N #1
  {
    \box_move_down:nn
      { ( \box_ht:N #1 - 0.8\l_@@_outer_unit_dim ) / 2 }
      { \box_use_drop:N #1 }
  }
\box_new:N \l_@@_opening_box
\box_new:N \l_@@_closing_box
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_set_before_skip:}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_set_before_skip:
  {
    \tl_if_empty:NTF \l_@@_before_skip_tl
      { \bool_set_false:N \l_@@_before_skip_bool }
      {
        \bool_if:NT \l_@@_before_skip_bool
          {
            \skip_set:Nn \l_@@_before_skip
              { \l_@@_before_skip_tl }
            \dim_compare:nNnF \l_@@_remaining_width_dim = \c_max_dim
              {
                \dim_sub:Nn \l_@@_remaining_width_dim
                  {
                      \l_@@_before_skip
                    - \tex_glueshrink:D \l_@@_before_skip
                  }
              }
          }
      }
  }
\bool_new:N \l_@@_before_skip_bool
\skip_new:N \l_@@_before_skip
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_set_lines:n}
%    \begin{macrocode}
\cs_new_protected:Npn \@@_set_lines:n #1
  {
    \int_compare:nNnTF {#1} > \c_zero_int
      {
        \int_set:Nn \l_@@_lines_int {#1}
        \@@_make_parshape:n { \l_@@_lines_int }
      }
      { \msg_error:nn { jiazhu } { invalid-number } }
  }
\cs_new_protected:Npn \@@_make_parshape:n #1
  {
    \cs_set_protected_nopar:Npx \@@_parshape:
      {
        \tex_parshape:D
          \int_eval:n { #1 + 1 } ~
          \prg_replicate:nn
            {#1} { \c_zero_dim \l_@@_remaining_width_dim }
          \c_zero_dim \c_max_dim \scan_stop:
      }
  }
\int_new:N \l_@@_lines_int
\cs_new_eq:NN \@@_parshape: \prg_do_nothing:
\msg_new:nnn { jiazhu } { invalid-number }
  { Please~specify~a~positive~integer. }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_set_alignment:n, \@@_alignment:}
%    \begin{macrocode}
\cs_new_protected:Npn \@@_set_alignment:n #1
  { \cs_set_eq:Nc \@@_alignment: { @@_alignment_ #1 : } }
\cs_new_protected_nopar:Npn \@@_alignment_justified:
  {
    \skip_zero:N \tex_leftskip:D
    \skip_zero:N \tex_rightskip:D
    \skip_set_eq:NN \tex_parfillskip:D \c_@@_fil_skip
  }
\cs_new_protected_nopar:Npn \@@_alignment_left:
  {
    \skip_zero:N \tex_leftskip:D
    \skip_set_eq:NN \tex_rightskip:D \l_@@_alignment_skip
    \skip_set_eq:NN \tex_parfillskip:D \c_@@_fil_skip
  }
\cs_new_protected_nopar:Npn \@@_alignment_right:
  {
    \skip_set_eq:NN \tex_leftskip:D \l_@@_alignment_skip
    \skip_zero:N \tex_rightskip:D
    \skip_zero:N \tex_parfillskip:D
  }
\cs_new_protected_nopar:Npn \@@_alignment_centered:
  {
    \skip_set_eq:NN \tex_leftskip:D \l_@@_alignment_skip
    \skip_set_eq:NN \tex_rightskip:D \l_@@_alignment_skip
    \skip_zero:N \tex_parfillskip:D
  }
\cs_new_protected_nopar:Npn \@@_alignment_distributed:
  {
    \skip_zero:N \tex_leftskip:D
    \skip_zero:N \tex_rightskip:D
    \skip_zero:N \tex_parfillskip:D
    \int_set_eq:NN \tex_tolerance:D \c_max_int
  }
\skip_new:N \l_@@_alignment_skip
\cs_new_eq:NN \@@_alignment: \@@_alignment_justified:
\skip_const:Nn \c_@@_fil_skip { \c_zero_dim plus 1fil }
\skip_set_eq:NN \l_@@_alignment_skip \c_@@_fil_skip
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_processing:}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_processing:
  {
      \@@_split_lines:
      \@@_put_closing_box:
      \@@_good_break:
      \@@_hskip:N \l_@@_after_skip_tl
    \group_end:
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_good_break:}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_good_break:
  {
    \skip_horizontal:N \l_@@_good_break_skip
    \tex_penalty:D -100 ~
    \skip_horizontal:n { -\l_@@_good_break_skip }
  }
\skip_new:N \l_@@_good_break_skip
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_hskip:N}
%    \begin{macrocode}
\cs_new_protected:Npn \@@_hskip:N #1
  { \tl_if_empty:NF #1 { \skip_horizontal:n {#1} } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_split_lines:}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_split_lines:
  {
    \dim_set:Nn \l_@@_width_dim
      {
        \dim_max:nn
          { \l_@@_unit_dim }
          { \box_wd:N \l_@@_text_box / \l_@@_lines_int }
      }
    \dim_compare:nNnTF \l_@@_width_dim > \l_@@_remaining_width_dim
      { \@@_split_parshape_lines: }
      { \@@_typeset_remaining: }
  }
\dim_new:N \l_@@_width_dim
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_split_parshape_lines:}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_split_parshape_lines:
  {
    \dim_compare:nNnTF \l_@@_remaining_width_dim < \l_@@_unit_dim
      { \@@_split_parshape_lines_auxi: }
      { \@@_split_parshape_lines_auxii: }
  }
\cs_new_protected_nopar:Npn \@@_split_parshape_lines_auxi:
  {
    \@@_fill_newline:
    \dim_set:Nn \l_@@_remaining_width_dim
      { \l_@@_line_width_dim - \box_wd:N \l_@@_opening_box }
    \bool_set_true:N \l_@@_full_line_bool
    \@@_split_lines:
  }
\cs_new_protected_nopar:Npn \@@_split_parshape_lines_auxii:
  {
    \vbox_set:Nn \l_@@_text_box
      {
        \bool_if:NTF \l_@@_full_line_bool
          { \int_set:Nn \tex_looseness:D { -1 } }
          { \@@_dim_normalize:N \l_@@_remaining_width_dim }
        \@@_parshape:
        \hbox_unpack_drop:N \l_@@_text_box
      }
    \vbox_set_split_to_ht:NNn \l_@@_typeset_box
      \l_@@_text_box { \l_@@_lines_int \tex_baselineskip:D }
    \vbox_set:Nn \l_@@_typeset_box
      { \vbox_unpack:N \l_@@_typeset_box }
    \bool_if:NF \l_@@_full_line_bool
      { \skip_horizontal:N \l_@@_unit_stretch_skip }
    \@@_typeset:
    \box_if_empty:NF \l_@@_text_box
      { \@@_split_remaining_lines: }
  }
\cs_new_protected_nopar:Npn \@@_fill_newline:
  { \tex_penalty:D 1000 \exp_stop_f: \tex_hfil:D \@@_newline: }
\cs_new_protected_nopar:Npn \@@_newline:
  { \tex_penalty:D -1000 \exp_stop_f: }
\box_new:N \l_@@_typeset_box
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_split_remaining_lines:}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_split_remaining_lines:
  {
    \@@_newline:
    \dim_set_eq:NN \l_@@_remaining_width_dim \l_@@_line_width_dim
    \bool_set_true:N \l_@@_full_line_bool
    \@@_extract_hbox:Nn \l_@@_text_box
      { \tex_unskip:D \tex_unskip:D \tex_unpenalty:D }
    \@@_split_lines:
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_extract_hbox:Nn}
% 从 \tn{vbox} 中取出 \tn{hbox}。
%    \begin{macrocode}
\cs_new_protected:Npn \@@_extract_hbox:Nn #1#2
  {
    \vbox_set:Nn #1
      {
        \vbox_unpack_drop:N #1
        \box_gset_to_last:N \g_@@_last_box
      }
    \hbox_set:Nn #1
      { \hbox_unpack_drop:N \g_@@_last_box #2 }
  }
\box_new:N \g_@@_last_box
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_dim_normalize:N}
%    \begin{macrocode}
\cs_new_protected:Npn \@@_dim_normalize:N #1
  {
    \dim_set:Nn #1
      {
        \int_div_truncate:nn {#1} { \l_@@_unit_dim }
        \l_@@_unit_dim
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_typeset:,\@@_typeset_remaining:}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_typeset:
  {
    \@@_put_opening_box:
    \@@_put_box:N \l_@@_typeset_box
  }
\cs_new_protected_nopar:Npn \@@_typeset_remaining:
  {
    \@@_dim_normalize:N \l_@@_width_dim
    \dim_set:Nn \l_@@_step_dim
      { \l_@@_unit_dim / \l_@@_lines_int }
    \skip_set_eq:NN \l_@@_alignment_skip \l_@@_unit_stretch_skip
    \@@_typeset_remaining_auxi:
  }
\cs_new_protected_nopar:Npn \@@_typeset_remaining_auxi:
  {
    \vbox_set:Nn \l_@@_typeset_box
      {
        \@@_alignment:
        \dim_set_eq:NN \tex_hsize:D \l_@@_width_dim
        \hbox_unpack:N \l_@@_text_box \par
        \int_gset_eq:NN \g_@@_lines_int \tex_prevgraf:D
      }
    \int_compare:nNnTF \g_@@_lines_int > \l_@@_lines_int
      { \@@_typeset_remaining_auxii: }
      { \@@_typeset_remaining_auxiii: }
  }
\cs_new_protected_nopar:Npn \@@_typeset_remaining_auxii:
  {
    \dim_add:Nn \l_@@_width_dim { \l_@@_step_dim }
    \@@_typeset_remaining_auxi:
  }
\cs_new_protected_nopar:Npn \@@_typeset_remaining_auxiii:
  {
    \@@_extract_max_width:N \l_@@_typeset_box
    \box_set_wd:Nn \l_@@_typeset_box
      { \dim_min:nn { \l_@@_max_dim } { \l_@@_width_dim } }
    \int_compare:nNnF \g_@@_lines_int = \l_@@_lines_int
      {
        \box_set_ht:Nn \l_@@_typeset_box
          {
            \int_eval:n { \l_@@_lines_int - \g_@@_lines_int }
            \tex_baselineskip:D + \box_ht:N \l_@@_typeset_box
          }
      }
    \@@_typeset:
  }
\dim_new:N \l_@@_step_dim
\int_new:N \g_@@_lines_int
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_extract_max_width:N}
% 获取盒子中的实际最大行宽。
%    \begin{macrocode}
\cs_new_protected:Npn \@@_extract_max_width:N #1
  {
    \dim_zero:N \l_@@_max_dim
    \box_if_empty:NF #1
      {
        \box_set_eq:NN \l_@@_tmpa_box #1
        \dim_set:Nn \l_@@_width_dim { \box_wd:N #1 }
        \@@_extract_max_width_auxi:
      }
  }
\cs_new_protected_nopar:Npn \@@_extract_max_width_auxi:
  {
    \vbox_set_split_to_ht:NNn \l_@@_tmpb_box
      \l_@@_tmpa_box { \tex_baselineskip:D }
    \@@_extract_hbox:Nn \l_@@_tmpb_box
      { \tex_unskip:D \tex_unskip:D \tex_unpenalty:D }
    \dim_set:Nn \l_@@_max_dim
      {
        \dim_max:nn
          { \l_@@_max_dim }
          { \box_wd:N \l_@@_tmpb_box }
      }
    \dim_compare:nNnT
      { \box_wd:N \l_@@_tmpb_box } > \l_@@_width_dim
      { \@@_extract_max_width_auxii: }
    \box_if_empty:NF \l_@@_tmpa_box
      { \@@_extract_max_width_auxi: }
  }
\cs_new_protected_nopar:Npn \@@_extract_max_width_auxii:
  {
    \hbox_set_to_wd:Nnn \l_@@_tmpb_box
      { \l_@@_width_dim }
      { \hbox_unpack_drop:N \l_@@_tmpb_box }
%    \end{macrocode}
% \tn{badness} 等于 \num{1000000} 表示盒子宽度溢出了。
%    \begin{macrocode}
    \int_compare:nNnF \tex_badness:D < { 1 000 000 }
      {
        \dim_add:Nn \l_@@_width_dim { \l_@@_step_dim }
        \@@_extract_max_width_auxii:
      }
  }
\dim_new:N \l_@@_max_dim
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_add_shortcut:n, \@@_remove_shortcuts:n}
% 设置和删除快捷命令。保险起见，我们只在文档开始时才实际设置快捷命令。
%    \begin{macrocode}
\AtBeginDocument { \@@_activate_shortcut: }
\cs_new_protected_nopar:Npn \@@_activate_shortcut:
  {
    \seq_if_empty:NF \l_@@_shortcut_seq
      {
        \seq_map_function:NN
          \l_@@_shortcut_seq \@@_add_shortcut_document:n
      }
    \cs_set_eq:NN \@@_add_shortcut_aux:n \@@_add_shortcut_document:n
    \cs_set_eq:NN \@@_remove_shortcut:n \@@_remove_shortcut_document:n
  }
\cs_new_protected:Npn \@@_add_shortcut:n #1
  {
    \tl_if_blank:nF {#1}
      { \@@_add_shortcut_aux:n {#1} }
  }
\cs_new_protected_nopar:Npn \@@_add_shortcut_aux:n
  { \seq_put_right:Nn \l_@@_shortcut_seq }
\cs_new_protected:Npn \@@_remove_shortcuts:n #1
  {
    \tl_map_inline:nn {#1}
      { \exp_args:Nf \@@_remove_shortcut:n { \int_to_arabic:n { `##1 } } }
  }
\cs_new_protected:Npn \@@_add_shortcut_document:n #1
  {
    \tl_if_single_token:nTF {#1}
      { \@@_set_shortcut_group:N #1 }
      { \@@_set_shortcut_delimiter:NNw #1 \q_stop }
  }
\cs_new_protected:Npn \@@_set_shortcut_group:N #1
  { \exp_args:Nf \@@_set_shortcut_group:n { \int_to_arabic:n { `#1 } } }
\cs_new_protected:Npn \@@_set_shortcut_group:n #1
  {
    \@@_save_shortcut:n {#1}
    \char_set_active_eq:nN {#1} \jiazhu
  }
\cs_new_protected:Npn \@@_set_shortcut_delimiter:NNw #1#2#3 \q_stop
  {
    \@@_set_shortcut_delimiter:NNf #1#2
      { \int_to_arabic:n { `#1 } }
  }
\cs_new_protected:Npn \@@_set_shortcut_delimiter:NNn #1#2
  {
    \str_if_eq:nnTF {#1} {#2}
      { \@@_set_shortcut_delimiter:n }
      { \@@_set_shortcut_delimiter:Nn #2 }
  }
\cs_generate_variant:Nn \@@_set_shortcut_delimiter:NNn { NNf }
\cs_new_protected:Npn \@@_set_shortcut_delimiter:n #1
  {
    \@@_active_char:nn
      { \@@_set_shortcut_delimiter:Nn } {#1} {#1}
  }
\cs_new_protected:Npn \@@_set_shortcut_delimiter:Nn #1#2
  {
    \exp_args:Nc \@@_set_shortcut_delimiter_aux:NNn
      { @@_shortcut_ #2 :w } #1 {#2}
  }
\cs_new_protected:Npn \@@_set_shortcut_delimiter_aux:NNn #1#2#3
  {
    \@@_save_shortcut:n {#3}
    \DeclareDocumentCommand #1 { +o +u{#2} }
      { \jiazhu:nn { ##1 } { ##2 } }
    \char_set_active_eq:nN {#3} #1
  }
\cs_new_protected:Npn \@@_save_shortcut:n #1
  {
    \prop_get:NnNF \l_@@_shortcut_prop {#1} \l_@@_catcode_tl
      {
        \exp_args:Nc \@@_save_active_char:Nn
          { @@_save_active_ #1 :w } {#1}
        \prop_put:Nnx \l_@@_shortcut_prop
          {#1} { \char_value_catcode:n {#1} }
        \char_set_catcode_active:n {#1}
      }
  }
\cs_new_protected_nopar:Npn \@@_remove_shortcut:n
  { \seq_remove_all:Nn \l_@@_shortcut_seq }
\cs_new_protected_nopar:Npn \@@_remove_shortcut_document:n #1
  {
    \prop_pop:NnNT \l_@@_shortcut_prop {#1} \l_@@_catcode_tl
      {
        \char_set_catcode:nn {#1} { \l_@@_catcode_tl }
        \exp_args:Nc \@@_restore_active_char:Nn
          { @@_save_active_ #1 :w } {#1}
      }
  }
\cs_new_protected:Npn \@@_save_active_char:Nn #1
  { \@@_active_char:nn { \cs_set_eq:NN #1 } }
\cs_new_protected:Npn \@@_restore_active_char:Nn #1#2
  {
    \char_set_active_eq:nN {#2} #1
    \cs_set_eq:NN #1 \tex_undefined:D
  }
\group_begin:
  \char_set_catcode_active:n { 0 }
  \cs_new_protected:Npn \@@_active_char:nn #1#2
    {
      \group_begin:
        \char_set_lccode:nn { 0 } {#2}
      \tex_lowercase:D { \group_end: #1 ^^@ }
    }
\group_end:
\tl_new:N \l_@@_catcode_tl
\seq_new:N \l_@@_shortcut_seq
\prop_new:N \l_@@_shortcut_prop
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{format}
% 定义键值选项。
%    \begin{macrocode}
\keys_define:nn { jiazhu }
  {
    format               .tl_set:N = \l_@@_format_tl ,
    beforeskip           .tl_set:N = \l_@@_before_skip_tl ,
    afterskip            .tl_set:N = \l_@@_after_skip_tl ,
    opening              .tl_set:N = \l_@@_opening_tl ,
    closing              .tl_set:N = \l_@@_closing_tl ,
    ratio                .fp_set:N = \l_@@_ratio_fp ,
    bracketratio         .fp_set:N = \l_@@_bracket_ratio_fp ,
    baselineshift       .dim_set:N = \l_@@_shift_dim ,
    lines                  .code:n = \@@_set_lines:n {#1} ,
    shortcut               .code:n = \@@_add_shortcut:n {#1} ,
    shortcut-              .code:n = \@@_remove_shortcuts:n {#1} ,
    alignment          .choices:nn =
      { justified , left , right , centered , distributed }
      { \@@_set_alignment:n { \l_keys_choice_tl } } ,
    ratio        .value_required:n = true ,
    bracketratio .value_required:n = true ,
    baselineshift.value_required:n = true ,
    lines        .value_required:n = true ,
    alignment    .value_required:n = true ,
    shortcut     .value_required:n = true ,
    shortcut-    .value_required:n = true ,
    beforeskip          .initial:n = \smallskipamount ,
    afterskip           .initial:n = \smallskipamount ,
    ratio               .initial:n = 0.5 ,
    bracketratio        .initial:n = 2.5 ,
    lines               .initial:n = 2 ,
    alignment           .initial:n = justified
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\jiazhu,\jiazhuset}
% 用户命令。
%    \begin{macrocode}
\NewDocumentCommand \jiazhu { +o +m }
  { \jiazhu:nn {#1} {#2} }
\NewDocumentCommand \jiazhuset { }
  { \keys_set:nn { jiazhu } }
%    \end{macrocode}
% \end{macro}
%
% \LuaTeX{} 单独处理。
%
%    \begin{macrocode}
\sys_if_engine_luatex:F
  {
    \box_new:N \l_@@_tmpa_box
    \box_new:N \l_@@_tmpb_box
    \file_input_stop:
  }
%    \end{macrocode}
%
% \begin{macro}{\@@_extract_max_width:N}
%    \begin{macrocode}
\cs_gset_protected:Npn \@@_extract_max_width:N #1
  {
    \box_if_empty:NTF #1
      { \dim_zero:N \l_@@_max_dim }
      {
        \int_set:Nn \l_@@_box_int {#1}
        \tex_luafunction:D \g_@@_box_max_width_func
        \dim_set_eq:NN \l_@@_width_dim \l_@@_max_dim
      }
  }
\int_new:N \l_@@_box_int
\newluafunction \g_@@_box_max_width_func
\cs_undefine:N \@@_extract_max_width_auxi:
\cs_undefine:N \@@_extract_max_width_auxii:
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{extract_max_width}
%    \begin{macrocode}
\group_begin:
\char_set_catcode_space:n { 32 }
\lua_now:e
  {
    jiazhu                = jiazhu or { }
    local jiazhu          = jiazhu
    local getbox          = tex.getbox
    local getcount        = tex.getcount
    local setdimen        = tex.setdimen
    local id_hlist        = node.id("hlist")
    local dnode           = node.direct
    local getlist         = dnode.getlist
    local todirect        = dnode.todirect
    local traverse_id     = dnode.traverse_id
    local rangedimensions = dnode.rangedimensions

    function jiazhu.extract_max_width ()
      local box   = getbox(getcount("l_@@_box_int"))
      local width = 0
      for hlist in traverse_id(id_hlist, getlist(todirect(box))) do
        local w = rangedimensions(hlist, getlist(hlist))
        if w > width then width = w end
      end
      setdimen("l_@@_max_dim", width)
    end

    local t = lua.get_functions_table()
    t[\int_use:N \g_@@_box_max_width_func] = jiazhu.extract_max_width
  }
\group_end:
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
%</package>
%    \end{macrocode}
%
% \end{implementation}
%
% \Finale
%
% \endinput
%
% \DisableImplementation
%
% \begin{implementation}
%
% \section{测试文件}
%
%    \begin{macrocode}
%<*test>
%    \end{macrocode}
% 例子来源于 Dian YIN (yindian@ustc) 的 \pkg{gezhu} 宏包。
%    \begin{macrocode}
\documentclass{ctexart}

\usepackage{jiazhu}

\jiazhuset { opening = 〔 , closing = 〕 , shortcut = | }

\ExplSyntaxOn
  \cs_if_exist_use:NT \xeCJKsetup
    { { AllowBreakBetweenPuncts } }
\ExplSyntaxOff

\begin{document}

\setlength\parskip{30pt}

%%\sloppy

\loop
\noindent\hrulefill\par
\the\hsize\par

世祖光武皇帝讳秀，字文叔，|{测礼“{祖有功而宗有德}”，光武中兴，故庙称世祖。谥法：“能绍前业曰光，克定祸乱曰武。”伏侯古今注曰：“秀之字曰茂。伯、仲、叔、季，兄弟之次。长兄伯升，次仲，故字文叔焉。”}南阳蔡阳人，|{南阳，郡，今邓州县也。蔡阳，县，故城在今随州枣阳县西南。}高祖九世之孙也，出自景帝生长沙定王发。|{长沙，郡，今潭州县也。}发生舂陵节侯买，|{舂陵，乡名，本属零陵泠道县，在今永州唐兴县北，元帝时徙南阳，仍号舂陵，故城在今随州枣阳县东。事具宗室四王传。}买生郁林太守外，|{郁林，郡，今贵州县。前书曰：“郡守，秦官。秩二千石。景帝更名太守。”}外生钜鹿都尉回，|{钜鹿，郡，今邢州县也。前书曰：“都尉，本{郡尉}，秦官也。掌佐守，典武职，秩比二千石。景帝更名都尉。”}回生南顿令钦，|{南顿，县，属汝南郡，故城在今陈州项城县西。前书曰：“令、长，皆秦官也。万户以上为令，秩千石至六百石；不满万户为长，秩五百石至三百石。”}钦生光武。光武年九岁而孤，养于叔父良。

身长七尺三寸，美须眉，大口，隆准，日角。|{隆，高也。许负云：“鼻头为准。”郑玄尚书中候注云：“日角谓庭中骨起，状如日。”}性勤于稼穑，|{种曰稼，敛曰穑。}而兄伯升好侠养士，常非笑光武事田业，比之高祖兄仲。|{仲，合阳侯喜也，能为产业。见前书。}王莽天凤中，|{王莽始建国六年改为天凤。}乃之长安，受尚书，略通大义。|{东观记曰：“受尚书于中大夫庐江许子威。资用乏，与同舍生韩子合钱买驴，令从者僦，以给诸公费。”}

莽末，天下连岁灾蝗，寇盗锋起。|{言贼锋锐竞起。字或作“蜂”，谕多也。}地皇三年，|{天凤六年改为地皇。}南阳荒饥，|{《韩诗外传》曰：“一谷不升曰歉，二谷不升曰饥，三谷不升曰馑，四谷不升曰荒，五谷不升曰大侵。”}诸家宾客多为小盗。光武避吏新野，|{新野属南阳郡，今邓州县。《续汉书》曰：“伯升宾客劫人，上避吏于新野邓晨家。”}因卖谷于宛。|{《东观记》曰：“时南阳旱饥，而上田独收。”宛，县，属南阳郡，故城今邓州南阳县也。}宛人李通等以图谶说光武云：“刘氏复起，李氏为辅。”|{图，《河图》也。谶，符命之书。谶，验也。言为王者受命之征验也。《易·坤灵图》曰：“汉之臣李阳也。”}光武初不敢当，然独念兄伯升素结轻客，必举大事，且王莽败亡已兆，天下方乱，遂与定谋，于是乃市兵弩。十月，与李通从弟轶等起于宛，时年二十八。

十一月，有星孛于张。|{《前书音义》曰：“孛星光芒短，蓬然。张，南方宿也。”《续汉志》曰：“张为周地。星孛于张，东南行即翼、轸之分。翼、轸，楚地，是楚地将有兵乱。后一年正月，光武起兵舂陵，攻南阳，斩阜、赐等，杀其士众数万人。光武都洛阳，居周地，除秽布新之象。”}光武遂将宾客还舂陵。时伯升已会众起兵。初，诸家子弟恐惧，皆亡逃自匿，曰“伯升杀我”。及见光武绛衣大冠，|{董巴《舆服志》曰：“大冠者，谓武冠，武官冠之。”《东观记》曰：“上时绛衣大冠，将军服也。”}皆惊曰“谨厚者亦复为之”，乃稍自安。伯升于是招新市、平林兵，|{新市，县，属江夏郡，故城在今郢州富水县东北。平林，地名，在今随州随县东北。}与其帅王凤、陈牧西击长聚。|{《广雅》曰：“聚，居也，音慈谕反。”《前书音义》曰：“小于乡曰聚。”}光武初骑牛，杀新野尉乃得马。|{《前书》曰，尉，秦官，秩四百石至二百石也。}进屠唐子乡，|{《例》曰：“多所诛杀曰屠。”唐子乡有唐子山，在今唐州湖阳县西南。}又杀湖阳尉。|{湖阳属南阳郡，今唐州县也。《东观记》曰：“刘终诈称江夏吏，诱杀之。”}军中分财物不均，众恚恨，欲反攻诸刘。光武敛宗人所得物，悉以与之，众乃悦。进拔棘阳，|{县名，属南阳郡，在棘水之阳，古谢国也，故城在今唐州湖阳县西北。棘音己力反。}与王莽前队大夫甄阜、|{王莽置六队，郡置大夫一人，职如太守。南阳为前队，河内为后队，颍川为左队，弘农为右队，河东为兆队，荥阳为祈队。队音遂。}属正梁丘赐|{王莽每队置属正一人，职如都尉。}战于小长安，|{《续汉书》曰淯阳县有小长安聚，故城在今邓州南阳县南。}汉军大败，还保棘阳。


\ifdim\hsize > 5cm %
  \advance\hsize by -4pt %
\repeat

\end{document}
%    \end{macrocode}
%
%    \begin{macrocode}
%</test>
%    \end{macrocode}
%
% \end{implementation}
%
% \Finale
%
\endinput
